package com.ruoyi.common.utils;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

/**
 * @desc 身份证工具类
 * @auth llp
 * @date 2022/7/7 16:13
 */
public class IdCardUtils {

    /** 检验码：余数作为索引，值代表所替换的值 */
    private static final String[] CHECK_INDEX = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
    /** 居民身份证 正则表达式 */
    private static final String SECOND_ID_CARD_REGULAR_EXP = "(^\\d{18}$)|(^\\d{17}(\\d|X|x)$|(^\\d{15}$))";
    /** 居民身份证 年份所在位数 */
    private static final int ID_CARD_YEAR_INDEX = 6;
 
    /** 第一代居民身份证长度 */
    private static final int FIRST_ID_CARD_LENGTH = 15;
    /** 第一代居民身份证 年份值 */
    private static final String FIRST_ID_CARD_YEAR = "19";
 
    /** 第二代居民身份证长度 */
    private static final int SECOND_ID_CARD_LENGTH = 18;
    /** 第二代居民身份证 校验码的模 */
    private static final int SECOND_ID_CARD_CHECK_MOD = 11;
 
    /** 性别表示的值 */
    private static final int MALE_SEX_INT = 1;
    private static final int FEMALE_SEX_INT = 2;

    private static final Map<String, String> PROVINCE_CODES = new HashMap<String, String>(32) {{
        put("11", "北京");
        put("12", "天津");
        put("13", "河北");
        put("14", "山西");
        put("15", "内蒙古");
        put("21", "辽宁");
        put("22", "吉林");
        put("23", "黑龙江");
        put("31", "上海");
        put("32", "江苏");
        put("33", "浙江");
        put("34", "安徽");
        put("35", "福建");
        put("37", "山东");
        put("41", "河南");
        put("42", "湖北");
        put("43", "湖南");
        put("44", "广东");
        put("45", "广西");
        put("46", "海南");
        put("50", "重庆");
        put("51", "四川");
        put("52", "贵州");
        put("53", "云南");
        put("54", "西藏");
        put("61", "陕西");
        put("62", "甘肃");
        put("63", "青海");
        put("64", "宁夏");
        put("65", "新疆维吾尔");
        put("71", "台湾");
        put("81", "香港");
        put("82", "澳门");
    }};


    private IdCardUtils() {}

    /**
     * @desc 通过身份证获取年龄
     * @auth llp
     * @date 2022/7/11 17:09
     * @param idCard 身份证
     * @return java.lang.String
     */
    public static int getAge(String idCard){
        if (!isIdCard(idCard)){
            return -1;
        }
        // 获取身份证的出生年月日串
        String birth = getBirthDayStr(idCard);
        // 获取年月日
        int year = Integer.parseInt(birth.substring(0, 4));
        int month = Integer.parseInt(birth.substring(4, 6));
        int day = Integer.parseInt(birth.substring(6, 8));
        // 计算年龄
        Calendar cal = Calendar.getInstance();
        int age = cal.get(Calendar.YEAR) - year;
        // 周岁计算
        boolean monthLtFlag = cal.get(Calendar.MONTH) + 1 < month;
        boolean monthDayFlag = cal.get(Calendar.MONTH) + 1 == month && cal.get(Calendar.DATE) < day;
        if ( monthLtFlag || monthDayFlag){
            age--;
        }
        return age;
    }

    // 通过身份证获取省份
    public static String getProvinceByIdCard(String idCard) {
        if (idCard == null || idCard.length() != 18) {
            return null; // 身份证号长度不正确
        }
        // 前6位为地址码，其中前两位代表省份
        String provinceCode = idCard.substring(0, 2);

        return PROVINCE_CODES.getOrDefault(provinceCode, null); // 返回对应的省份名称，如果不存在则返回null
    }

    /**
     * @desc 通过身份证获取出生日期
     * @auth llp
     * @date 2022/7/15 16:39
     * @param idCard 身份证
     * @return java.lang.String
     */
    public static String getBirthDay(String idCard){
        if (!isIdCard(idCard)){
            return "idCard error!";
        }
        // 获取身份证的出生年月日串
        String birth = getBirthDayStr(idCard);
        // 获取年月日
        int year = Integer.parseInt(birth.substring(0, 4));
        int month = Integer.parseInt(birth.substring(4, 6));
        int day = Integer.parseInt(birth.substring(6, 8));
        return year + "-" + month + "-" + day;
    }
 
    /**
     * 通过身份证获取性别
     * @param idCard:	身份证号码
     * @return: int
     * @author: kenn
     * @date: 2023/12/6 18:07
     */
    public static int getSex(String idCard){
        if (!isIdCard(idCard)){
            return -1;
        }
        // 默认值
        int sex = -1;
        // 15 位身份证
        if (idCard.length() == FIRST_ID_CARD_LENGTH){
            String sexStr = idCard.substring(14, 15);
            // 偶数表示女性，奇数表示男性
            if (Integer.parseInt(sexStr) % 2 == 0){
                sex = FEMALE_SEX_INT;
            }else {
                sex = MALE_SEX_INT;
            }
        }
        // 18 位身份证
        if (idCard.length() == SECOND_ID_CARD_LENGTH){
            String sexStr = idCard.substring(16, 17);
            // 偶数表示女性，奇数表示男性
            if (Integer.parseInt(sexStr) % 2 == 0){
                sex = FEMALE_SEX_INT;
            }else {
                sex = MALE_SEX_INT;
            }
        }
        return sex;
    }
 
    /**
     * @desc 检测是否为身份证
     * @auth llp
     * @date 2022/7/11 15:32
     * @param idCard 身份证
     * @return boolean
     */
    public static boolean isIdCard(String idCard){
        if (StringUtils.isBlank(idCard)){
            return false;
        }
        StringBuilder idCardBuilder = new StringBuilder(idCard);
        // 正则表达式
        boolean matches = idCard.matches(SECOND_ID_CARD_REGULAR_EXP);
        // 第二代身份证的验证
        if (matches && idCardBuilder.length() == SECOND_ID_CARD_LENGTH){
            int index = checkIndex(idCardBuilder);
            // 获取传入身份证的检验码
            String check = String.valueOf(idCardBuilder.charAt(idCardBuilder.length()-1));
            // 检验码校验
            return StringUtils.equalsIgnoreCase(CHECK_INDEX[index], check);
        }
        return matches;
    }
 
    /**
     * @desc 将 15位身份证号码转为 18位身份证号码
     * @auth llp
     * @date 2022/7/11 15:13
     * @param idCard 身份证号码
     * @return java.lang.String
     */
    public static String idCardNumber15To18(String idCard){
        if (!isIdCard(idCard) || idCard.length() != FIRST_ID_CARD_LENGTH){
            return "idCard error!";
        }
        StringBuilder idCardBuilder = new StringBuilder(idCard);
        // 在 第6位后插入年份
        idCardBuilder.insert(ID_CARD_YEAR_INDEX, FIRST_ID_CARD_YEAR);
        int index = checkIndex(idCardBuilder);
        // 根据余数在校验码数组里取值
        idCardBuilder.append(CHECK_INDEX[index]);
        return idCardBuilder.toString();
    }
 
    /**
     * @desc 将 18位身份证号码转为 15位身份证号码
     * @auth llp
     * @date 2022/7/15 16:40
     * @param idCard 身份证号码
     * @return java.lang.String
     */
    public static String idCardNumber18To15(String idCard){
        if (!isIdCard(idCard) || idCard.length() != SECOND_ID_CARD_LENGTH){
            return "idCard error!";
        }
        // 去掉18位身份证的年份前两位 去掉校验码
        return idCard.substring(0, 5)+idCard.substring(8, 17);
    }

    /**
     * 根据身份证前两位获取所属省份
     * @param code:	身份证前两位
     * @return: java.lang.String
     * @author: kenn
     * @date: 2023/12/6 17:57
     */
    public static String getProvince(int code) {
        switch (code) {
            case 11:
                return "北京市";
            case 12:
                return "天津市";
            case 13:
                return "河北省";
            case 14:
                return "山西省";
            case 15:
                return "内蒙古自治区";
            case 21:
                return "辽宁省";
            case 22:
                return "吉林省";
            case 23:
                return "黑龙江省";
            case 31:
                return "上海市";
            case 32:
                return "江苏省";
            case 33:
                return "浙江省";
            case 34:
                return "安徽省";
            case 35:
                return "福建省";
            case 36:
                return "江西省";
            case 37:
                return "山东省";
            case 41:
                return "河南省";
            case 42:
                return "湖北省";
            case 43:
                return "湖南省";
            case 44:
                return "广东省";
            case 45:
                return "广西壮族自治区";
            case 46:
                return "海南省";
            case 50:
                return "重庆市";
            case 51:
                return "四川省";
            case 52:
                return "贵州省";
            case 53:
                return "云南省";
            case 54:
                return "西藏自治区";
            case 61:
                return "陕西省";
            case 62:
                return "甘肃省";
            case 63:
                return "青海省";
            case 64:
                return "宁夏回族自治区";
            case 65:
                return "新疆维吾尔自治区";
            case 71:
                return "台湾省";
            case 81:
                return "香港特别行政区";
            case 82:
                return "澳门特别行政区";
            default:
                return "未知";
        }
    }

    /**
     * 根据身份证前四位获取安徽各市
     * @param code:	身份证前两位
     * @return: java.lang.String
     * @author: kenn
     * @date: 2023/12/6 17:57
     */
    public static String getMarket(int code) {
        switch (code) {
            case 3401:
                return "合肥市";
            case 3402:
                return "芜湖市";
            case 3403:
                return "蚌埠市";
            case 3404:
                return "淮南市";
            case 3405:
                return "马鞍山市";
            case 3406:
                return "淮北市";
            case 3407:
                return "铜陵市";
            case 3408:
            case 3428:
                return "安庆市";
            case 3410:
            case 3427:
                return "黄山市";
            case 3411:
            case 3423:
                return "滁州市";
            case 3412:
            case 3421:
                return "阜阳市";
            case 3413:
            case 3422:
                return "宿州市";
            case 3414:
            case 3426:
                return "巢湖市";
            case 3415:
            case 3424:
                return "六安市";
            case 3416:
                return "亳州市";
            case 3417:
            case 3429:
                return "池州市";
            case 3418:
            case 3425:
                return "宣城市";
            default:
                return "未知";
        }
    }
 
    /**
     * @desc 计算出校验码所在校验码数组的下标值
     * @auth llp
     * @date 2022/7/13 9:51
     * @param idCardBuilder 身份证
     * @return int 检验码下标
     */
    private static int checkIndex(StringBuilder idCardBuilder){
        // 判断传入的是17位还是18位身份证号
        int length = idCardBuilder.length() == SECOND_ID_CARD_LENGTH ? idCardBuilder.length()-1 : idCardBuilder.length();
        // 计算出校验码
        int sum = 0;
        // length=17, i=0、2、3...16
        for (int i = 0; i < length; i++) {
            // 前17位数字
            int numVal = Integer.parseInt(String.valueOf(idCardBuilder.charAt(i)));
            int numMultiple = (int) (Math.pow(2, length - i) % SECOND_ID_CARD_CHECK_MOD);
            sum += (numVal * numMultiple);
        }
        // 总和取模11
        return sum % SECOND_ID_CARD_CHECK_MOD;
    }
 
    /**
     * @desc 通过身份证获取出生日期的 str 串
     * @auth llp
     * @date 2022/7/15 16:37
     * @param idCard 身份证
     * @return java.lang.String
     */
    private static String getBirthDayStr(String idCard){
        // 获取身份证的出生年月日串
        if (idCard.length() == FIRST_ID_CARD_LENGTH){
            return FIRST_ID_CARD_YEAR + idCard.substring(ID_CARD_YEAR_INDEX, 12);
        }
        if (idCard.length() == SECOND_ID_CARD_LENGTH){
            return idCard.substring(ID_CARD_YEAR_INDEX, 14);
        }
        return StringUtils.EMPTY;
    }

}